
package com.hisense.settings.util;

import android.app.ActivityManager;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.res.AssetManager;
import android.media.AudioManager;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.NetworkInfo.State;
import android.os.IBinder;
import android.os.SystemClock;
import android.provider.Settings;
import android.provider.Settings.SettingNotFoundException;
import android.util.Log;
import android.view.KeyEvent;

/*import com.marvell.willowtv.framework.features.TvFramework;
import com.marvell.willowtv.framework.model.atsc.USDTVCurrentTime;
import com.marvell.willowtv.framework.model.avsettings.ITvRemoteService;*/


import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.net.InetAddress;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Properties;

/**
 * Utility Class of GTV system methods
 * @author Marvell
 * @date 04 Dec 2012
 */
public class HisUtils {

    private static final String TAG = "HisUtils";
    public final static int ONE_MINUTE = 60 * 1000;
    public final static int ONE_SECOND = 1000;
    public static String LOCATION_LINEUP_LOOKUP = "location_lineup_lookup";

    private static long mSleepEndTime = 0;

    //private static ITvRemoteService mITvRemoteService = null;
    private static IBinder mTvRemoteServiceBinder;
    public static final String TVSERVICE_BOUND = "com.marvell.willowtv.settings.TVSERVICE_BOUND";

    public static HashMap<Integer, Integer> keyCodeMapping;

    public static final String ACTION_REQUEST_SHUTDOWN =
            "android.intent.action.ACTION_REQUEST_SHUTDOWN";
    public static final String EXTRA_KEY_CONFIRM = "android.intent.extra.KEY_CONFIRM";
    // public static final String ACTION_DO_POWER_OFF =
    // "com.marvell.AppKiller.DO_POWER_OFF";
    // public static final String NEED_CONFIRM_EXTRA = "NEED_CONFIRM";

    public static final String TUNER_DEVICE_ID = "com.marvell.willowtv.controller.device.TUNER";

    static {
        keyCodeMapping = new HashMap<Integer, Integer>();
        keyCodeMapping.put(KeyEvent.KEYCODE_0, 0);
        keyCodeMapping.put(KeyEvent.KEYCODE_1, 1);
        keyCodeMapping.put(KeyEvent.KEYCODE_2, 2);
        keyCodeMapping.put(KeyEvent.KEYCODE_3, 3);
        keyCodeMapping.put(KeyEvent.KEYCODE_4, 4);
        keyCodeMapping.put(KeyEvent.KEYCODE_5, 5);
        keyCodeMapping.put(KeyEvent.KEYCODE_6, 6);
        keyCodeMapping.put(KeyEvent.KEYCODE_7, 7);
        keyCodeMapping.put(KeyEvent.KEYCODE_8, 8);
        keyCodeMapping.put(KeyEvent.KEYCODE_9, 9);
    }

    /*****************************************************************/
    /******* Misc Utils ************/
    /*****************************************************************/

    /**
     * Returns true if Monkey is running.
     */
    public static boolean isMonkeyRunning() {
        return ActivityManager.isUserAMonkey();
    }

    /**
     * Reboots the device.
     */
    public static final void reboot(Context context) {

        // Do not reboot if on Mokey run.
        if (isMonkeyRunning()) {
            return;
        }

        Intent rebootIntent = new Intent(Intent.ACTION_REBOOT);
        // Flags that are required for WatchDog to not ignore the intent.
        rebootIntent.putExtra("nowait", 1);
        rebootIntent.putExtra("interval", 1);
        rebootIntent.putExtra("window", 0);
        context.sendBroadcast(rebootIntent);
    }

    public static boolean isSystemMute(Context context) {
        Boolean mute = false;
        if (context != null) {
            AudioManager mAudioManager = (AudioManager) context
                    .getSystemService(Context.AUDIO_SERVICE);
            // boolean mute =
            // mAudioManager.isStreamMute(AudioManager.STREAM_MUSIC);
            // mute = (Boolean) HisUtils.getValueByAPI(mAudioManager, "isStreamMute",
            //         AudioManager.STREAM_MUSIC);
	    mute = HisUtils.getValueByAPI_B(mAudioManager, "isMasterMute", false) ||
		    ((Boolean) HisUtils.getValueByAPI(mAudioManager, "isStreamMute",
			    AudioManager.STREAM_MUSIC)) ||
		    (mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC)
		     == 0 ? true : false);
	}
        Log.d(TAG, "mAudioManager.isStreamMute() = " + mute);
        return mute;
    }

    /*****************************************************************/
    /******* Network Utils ************/
    /*****************************************************************/

    public static boolean isWifiOnly() {
        return false;
    }

    public static boolean isValidIpAddress(String ipAddress, boolean allowEmptyValue) {
        if (ipAddress == null || ipAddress.length() == 0) {
            return allowEmptyValue;
        }

        int dotCount = 0;
        for (int i = 0; i < ipAddress.length(); i++) {
            if ('.' == ipAddress.charAt(i)) {
                dotCount++;
            }
        }

        if (dotCount != 3) {
            return false;
        }

        try {
            InetAddress.getByName(ipAddress);
            return true;
        } catch (Throwable ex) {
            return false;
        }
    }

    public static boolean isNetworkActive(ConnectivityManager manager, int connectionType) {
        if (manager == null) {
            Log.e(TAG, "Connectivity Manager is null!");
            return false;
        } else {
            NetworkInfo networkInfo = manager.getActiveNetworkInfo();

            if (networkInfo == null) {
                return false;
            }

            if (connectionType == networkInfo.getType()) {
                if (networkInfo.getState() == State.CONNECTED) {
                    return true;
                }
            }
            return false;
        }
    }

    public static boolean isNetworkConnected(Context context) {
        ConnectivityManager manager = (ConnectivityManager) context.getSystemService(
                Context.CONNECTIVITY_SERVICE);
        NetworkInfo info = manager.getActiveNetworkInfo();
        boolean connected = (info != null) && info.isConnected();
        return connected;
    }

    /*****************************************************************/
    /******* Java Reflection Utils ************/
    /*****************************************************************/

    /**
     * Create dynamically a object by its class name
     * @param className
     *            : name of class type
     */
    public static Object CreateObjectByClass(String className) {
        Object obj = null;
        if (!className.isEmpty()) {
            try {
                Class<?> c = Class.forName(className);
                obj = c.newInstance();
            } catch (Exception e) {
                Log.w(TAG, "CreateObjectByClass " + className + " exception " + e);
            }
        }
        return obj;
    }

    /**
     * Get class type by its class name
     * @param className
     *            : name of class type
     */
    public static Class<?> GetClassTypeByClassName(String className) {
        Class<?> c = null;
        if (!className.isEmpty()) {
            try {
                c = Class.forName(className);
            } catch (Exception e) {
                Log.w(TAG, "GetClassTypeByClassName " + className + " exception " + e);
            }
        }
        return c;
    }

    /**
     * Call API_obj.getAPI_name
     * @param API_obj
     *            : object of API class
     * @param API_name
     *            : name of API
     * @return int value
     **/
    public static int getValueByAPI(Object API_obj, String API_name) {
        int retVal = 0;
        Class<?> iClass = API_obj.getClass();
        try {
            Method getMethod = iClass.getMethod("get" + API_name);
            retVal = (Integer) getMethod.invoke(API_obj);
            Log.v(TAG, "getValueByAPI " + API_name + " return:" + retVal);
        } catch (Exception e) {
            Log.w(TAG, "getValueByAPI " + API_name + " exception " + e);
        }
        return retVal;
    }

    /**
     * Call API_obj.API_name with one param to return Object value
     * @param API_obj
     *            : object of API class
     * @param API_name
     *            : name of API
     * @param value
     *            : param of API
     * @return Object value
     **/
    public static Object getValueByAPI(Object API_obj, String API_name, int value) {
        Object retVal = null;
        Class<?> iClass = API_obj.getClass();
        try {
            Method getMethod = iClass.getMethod(API_name, int.class);
            retVal = getMethod.invoke(API_obj, value);
            Log.v(TAG, "getValueByAPI " + API_name + " return:" + retVal);
        } catch (Exception e) {
            Log.w(TAG, "getValueByAPI " + API_name + " exception " + e);
        }
        return retVal;
    }

    /**
     * Call API_obj.getAPI_name
     * @param API_obj
     *            : object of API class
     * @param API_name
     *            : name of API
     * @return int value
     **/
    public static String getValueByAPI_S(Object API_obj, String API_name) {
        String retVal = null;
        Class<?> iClass = API_obj.getClass();
        try {
            Method getMethod = iClass.getMethod("get" + API_name);
            retVal = (String) getMethod.invoke(API_obj);
            Log.v(TAG, "getValueByAPI " + API_name + " return:" + retVal);
        } catch (Exception e) {
            Log.w(TAG, "getValueByAPI " + API_name + " exception " + e);
        }
        return retVal;
    }

    /**
     * Call API_obj.getAPI_name
     * @param API_obj
     *            : object of API class
     * @param API_name
     *            : name of API
     * @return int value
     **/
    public static boolean getValueByAPI_B(Object API_obj, String API_name, boolean defaultv) {
        boolean retVal = defaultv;
        Class<?> iClass = API_obj.getClass();
        try {
            Method getMethod = iClass.getMethod(API_name);
            retVal = (Boolean) getMethod.invoke(API_obj);
            Log.v(TAG, "getValueByAPI " + API_name + " return:" + retVal);
        } catch (Exception e) {
            Log.w(TAG, "getValueByAPI " + API_name + " exception " + e);
        }
        return retVal;
    }

    /**
     * Call API_obj.setAPI_name(int value)
     * @param API_obj
     *            : object of API class
     * @param API_name
     *            : name of API
     * @param val
     *            : int value
     */
    public static void setValueByAPI(Object API_obj, String API_name, int val) {
        Class<?> iClass = API_obj.getClass();
        try {
            Method setMethod = iClass.getMethod("set" + API_name, new Class[] {
                    int.class
            });
            Log.v(TAG, "setValueByAPI " + API_name + " value:" + val);
            setMethod.invoke(API_obj, val);
        } catch (Exception e) {
            Log.w(TAG, "setValueByAPI " + API_name + " exception " + e);
        }
    }

    /**
     * Invoke static method by its class name and method name
     * @param className
     *            : name of class
     * @param methodName
     *            : name of method
     * @param args
     *            : array of object returned
     */
    public static Object invokeStaticMethod(String className, String methodName, Object[] args) {
        if (!className.isEmpty()) {
            try {
                Class<?> c = Class.forName(className);
                Class<?>[] argsClass = new Class[args.length];

                for (int i = 0, j = args.length; i < j; i++) {
                    argsClass[i] = args[i].getClass();
                }

                Method method = c.getMethod(methodName, argsClass);
                return method.invoke(null, args);
            } catch (Exception e) {
                Log.w(TAG, "invokeStaticMethod " + className + "."
                        + methodName + " exception " + e);
            }
        }

        return null;
    }

    /*****************************************************************/
    /******* File System Utils ************/
    /*****************************************************************/

    public static class SystemInfo {
        public static final String VERSION = "ro.marvell.build.version";
        public static final String MODULE_NUMBER = "ro.product.model";
        public static final String BUILD_TIME = "ro.build.date";

        public static String getString(String propName) {
            String lines = "";
            String ret = "";
            File propFile = new File("/system/build.prop");
            if (propFile.exists()) {
                try {
                    BufferedReader input = new BufferedReader(new FileReader(propFile));
                    try {
                        while ((lines = input.readLine()) != null) {
                            Log.d(TAG, "Build info:$$$$" + lines + "$$$$");
                            //delete the space on both sides of "=" in lines.
                            lines = lines.replaceAll(" += +", "=");
                            String key = lines.substring(0,
                                    (lines.indexOf('=') == -1 || (lines.indexOf('=') == 0)) ? 0
                                            : lines.indexOf('='));
                            Log.d(TAG, "Build info-key:$$$$" + key + "$$$$");
                            if (propName.equals(key)) {
                                ret = lines.substring(lines.lastIndexOf("=") + 1);
                            }
                        }
                    } finally {
                        input.close();
                    }
                } catch (Exception ioe) {
                    ioe.printStackTrace();
                    Log.d(TAG, "$$$$Exception occurred when reading build.prop file$$$$");
                }
            } else {
                Log.d(TAG, "build.prop does not exist");
            }
            return ret;
        }
    }

    /**
     * To get Properties instance for given File
     * @param file
     *            file name
     * @return Properties instance
     */
    public static Properties getPropertiesFile(final String file, final Context context) {

        Properties properties = new Properties();
        InputStream stream = null;
        try {
            AssetManager assets = context.getResources().getAssets();
            stream = assets.open(file);
            properties.load(stream);
        } catch (IOException e) {
            //ProgramaticException.displayException(context, TAG, e);
        } finally {
            if (stream != null) {
                try {
                    stream.close();
                } catch (IOException e) {
                    Log.e(TAG, " Exception occured when closing stream " + e);
                }
            }
        }
        return properties;
    }

    /*****************************************************************/
    /******* System time Utils ************/
    /*****************************************************************/

    public static long getRealTime() {
        return SystemClock.elapsedRealtime();
    }

    public static void startSleepTimer(final Context context, int timer) {
        Intent intent = new Intent(TvIntents.ACTION_START_TIMER_SLEEP);
        if (timer > 0) {
            intent.putExtra(TvIntents.EXTRA_TIMER_VALUE, timer);
            context.startService(intent);
            mSleepEndTime = getRealTime() + timer;
        } else {
            context.stopService(intent);
        }
    }

    public static int getSleepTimerRemainingMinutes() {
        long realTime = getRealTime();
        int minutes = 0;
        if (mSleepEndTime > realTime) {
            minutes = (int) ((mSleepEndTime - realTime + ONE_MINUTE - 1) / ONE_MINUTE);
        }

        return minutes;
    }

    public static void startAutoPowerOffTimer(final Context context, int timer) {
        Intent intent = new Intent(TvIntents.ACTION_START_TIMER_AUTO_POWER);
        if (timer > 0) {
            intent.putExtra(TvIntents.EXTRA_TIMER_VALUE, timer);
            context.startService(intent);
        } else {
            context.stopService(intent);
        }
    }

    public static void startNoSignalTimer(final Context context, int timer) {
        Intent intent = new Intent(TvIntents.ACTION_START_TIMER_NO_SIGNAL);
        if (timer > 0) {
            intent.putExtra(TvIntents.EXTRA_TIMER_VALUE, timer);
            context.startService(intent);
        } else {
            context.stopService(intent);
        }
    }

    /**
     * Set AlarmManager to send pending intent in future. Normally it is
     * triggered when activity/service/receiver is finished.
     * @param context
     * @param type
     *            0 - start service, 1 - broadcast, 2 - start activity
     * @param pendingTime
     *            the time in ms to send intent since now
     * @param intent
     *            the intent to send
     */
    public static void setAlarmStartPendingService(final Context context, int type,
            int pendingTime, Intent intent) {
        AlarmManager alarmManager = (AlarmManager) context
                .getSystemService(Context.ALARM_SERVICE);
        PendingIntent pendingIntent = null;
        switch (type) {
            case 0:
                pendingIntent = PendingIntent.getService(context, 007,
                        intent, PendingIntent.FLAG_CANCEL_CURRENT);
                break;
            case 1:
                pendingIntent = PendingIntent.getBroadcast(context, 007,
                        intent, PendingIntent.FLAG_CANCEL_CURRENT);
                break;
            case 2:
                pendingIntent = PendingIntent.getActivity(context, 007,
                        intent, PendingIntent.FLAG_CANCEL_CURRENT);
                break;
            default:
                return;
        }
        long triggerTime = getRealTime() + pendingTime;
        alarmManager.set(AlarmManager.ELAPSED_REALTIME, triggerTime, pendingIntent);
    }

    /*****************************************************************/
    /******* GTV Service Utils ************/
    /*****************************************************************/
    public static IBinder getServiceBinder(final String serviceName) {
        IBinder binder = null;
        int tryCount = 0;
        do {
            Object[] argArray = new Object[1];
            argArray[0] = serviceName;
            binder = (IBinder) HisUtils.invokeStaticMethod("android.os.ServiceManager",
                    "getService", argArray);
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                Log.w(TAG, "getService e = " + e);
            }
        } while (null == binder && tryCount++ < 10);

        return binder;
    }

    public static boolean isBinderAlive(IBinder binder) {
        boolean ret = true;
        try {
            ret = binder.isBinderAlive();
        } catch (Exception e) {
            Log.e(TAG, "isBinderAlive exception" + e);
            ret = false;
        }
        return ret;
    }

   /* private static final TvRemoteServiceConnect mTvRemoteServiceConnection =
            new HisUtils().new TvRemoteServiceConnect();
    public class TvRemoteServiceConnect implements ServiceConnection {
        public Context mTvContext;
        @Override
        public void onServiceDisconnected(ComponentName name) {
            // TODO Auto-generated method stub
        }

        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            mTvRemoteServiceBinder = service;
            if (mTvRemoteServiceBinder != null) {
                mITvRemoteService = ITvRemoteService.Stub
                        .asInterface(mTvRemoteServiceBinder);
                Intent intent = new Intent(TVSERVICE_BOUND);
                if (mTvContext != null) {
                    mTvContext.sendBroadcast(intent);
                }
            }
        }
    };

    public static void bindTvRemoteService(Context context) {
        Log.d(TAG, "bindTvRemoteService context=" + context);
        if (context != null&& getTvRemoteService() == null) {
            Intent tvRemoteintent = new Intent(TvIntents.ACTION_BIND_TV_REMOTE_SERVICE);
            mTvRemoteServiceConnection.mTvContext = context;
            context.bindService(tvRemoteintent, mTvRemoteServiceConnection,
                    Context.BIND_AUTO_CREATE);
        }
    }

    public static void unbindTvRemoteService(Context context) {
        Log.d(TAG, "unbindTvRemoteService context=" + context);
        if (context != null && getTvRemoteService() != null) {
            context.unbindService(mTvRemoteServiceConnection);
            mTvRemoteServiceBinder = null;
            mITvRemoteService = null;
        }
    }

    public static ITvRemoteService getTvRemoteService() {
        if ((mITvRemoteService == null || !isBinderAlive(mTvRemoteServiceBinder))
                && !TvFramework.getInstance().isPrototyping()) {
            mTvRemoteServiceBinder = getServiceBinder(TvIntents.TV_REMOTE_SERVICE_NAME);
            if (mTvRemoteServiceBinder != null) {
                mITvRemoteService = ITvRemoteService.Stub
                        .asInterface(mTvRemoteServiceBinder);
            }
        }
        return mITvRemoteService;
    }*/

    public static void doShutdown(final Context context) {
        Log.i(TAG, "doShutdown");

        // Intent intent = new Intent().setAction(ACTION_DO_POWER_OFF);
        // intent.putExtra(NEED_CONFIRM_EXTRA, false);
        // sendBroadcast(intent);

        Intent intent = new Intent(ACTION_REQUEST_SHUTDOWN);
        intent.putExtra(EXTRA_KEY_CONFIRM, false);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        context.startActivity(intent);
    }

    public static boolean isTimeAutomatic(Context context) {
        try {
            return Settings.System.getInt(context.getContentResolver(),
                    Settings.System.AUTO_TIME) > 0;
        } catch (SettingNotFoundException snfe) {
            return true;
        }
    }

    /*public static void syncPSIPDateTime(Context context) {
        boolean autoEnabled = isTimeAutomatic(context);
        boolean isNetConnected = isNetworkConnected(context);

        if (autoEnabled && !isNetConnected && Wrapper.getWrapperInstance().isDigitalChannel()) {
            USDTVCurrentTime currentTime = TvFramework.getInstance().getSystemInstance()
                    .getCurrentTime();

            Calendar c = Calendar.getInstance();
            c.set(Calendar.YEAR, currentTime.getYear());
            c.set(Calendar.MONTH, currentTime.getMonth() - 1);
            c.set(Calendar.DAY_OF_MONTH, currentTime.getDate());
            c.set(Calendar.HOUR_OF_DAY, currentTime.getHrs());
            c.set(Calendar.MINUTE, currentTime.getMins());
            c.set(Calendar.SECOND, currentTime.getSecs());

            long when = c.getTimeInMillis();
            if (when / 1000 < Integer.MAX_VALUE) {
                SystemClock.setCurrentTimeMillis(when);
            }
        }

    }*/

}
